using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.Xna.Framework;

namespace XnaDevRu.Bullet
{
	/// <summary>
	/// SphereSphereCollisionAlgorithm  provides sphere-sphere collision detection.
	/// Other features are frame-coherency (persistent data) and collision response.
	/// Also provides the most basic sample for custom/user btCollisionAlgorithm
	/// </summary>
	public class SphereTriangleCollisionAlgorithm : CollisionAlgorithm, IDisposable
	{
		private bool _ownManifold;
		private PersistentManifold _manifold;
		private bool _isSwapped;

		public SphereTriangleCollisionAlgorithm(PersistentManifold manifold, CollisionAlgorithmConstructionInfo collisionAlgorithmConstructionInfo, CollisionObject bodyA, CollisionObject bodyB, bool isSwapped)
			: base(collisionAlgorithmConstructionInfo)
		{
			_ownManifold = false;
			_manifold = manifold;
			_isSwapped = isSwapped;

			if (_manifold == null)
			{
				_manifold = Dispatcher.GetNewManifold(bodyA, bodyB);
				_ownManifold = true;
			}
		}

		public SphereTriangleCollisionAlgorithm(CollisionAlgorithmConstructionInfo collisionAlgorithmConstructionInfo)
			: base(collisionAlgorithmConstructionInfo) { }

		public override void ProcessCollision(CollisionObject bodyA, CollisionObject bodyB, DispatcherInfo dispatchInfo, ManifoldResult resultOut)
		{
			if (_manifold == null)
				return;

			SphereShape sphere = bodyA.CollisionShape as SphereShape;
			TriangleShape triangle = bodyB.CollisionShape as TriangleShape;

			/// report a contact. internally this will be kept persistent, and contact reduction is done
			resultOut.SetPersistentManifold(_manifold);
			SphereTriangleDetector detector = new SphereTriangleDetector(sphere, triangle);

			DiscreteCollisionDetectorInterface.ClosestPointInput input = new DiscreteCollisionDetectorInterface.ClosestPointInput();
			input.MaximumDistanceSquared = 1e30f;//todo: tighter bounds
			input.TransformA = bodyA.WorldTransform;
			input.TransformB = bodyB.WorldTransform;

			detector.GetClosestPoints(input, resultOut, null);
		}

		public override float CalculateTimeOfImpact(CollisionObject bodyA, CollisionObject bodyB, DispatcherInfo dispatchInfo, ManifoldResult resultOut)
		{
			//not yet
			return 1f;
		}

		public class CreateFunc : CollisionAlgorithmCreateFunction
		{
			public override CollisionAlgorithm CreateCollisionAlgorithm(CollisionAlgorithmConstructionInfo collisionAlgorithmConstructionInfo, CollisionObject bodyA, CollisionObject bodyB)
			{
				return new SphereTriangleCollisionAlgorithm(collisionAlgorithmConstructionInfo.Manifold, collisionAlgorithmConstructionInfo, bodyA, bodyB, IsSwapped);
			}
		}

		#region IDisposable Members
		public void Dispose()
		{
			if (_ownManifold)
				if (_manifold != null)
					Dispatcher.ReleaseManifold(_manifold);
		}
		#endregion
	}
}
